package model;

import java.util.Random;
import view.Boundary;
import cards.Card;
import cards.ConditionedPay;
import cards.ConditionedReceive;
import cards.GoToJail;
import cards.GoToReceiveStart;
import cards.GoToShipping;
import cards.Move;
import cards.Pay;
import cards.Receive;
import cards.ReceiveBirthday;

public class Deck {
	private static Card[] cards;
	private static Card[] discarded;
	
	public Deck() {
		cards = new Card[50];
		discarded = new Card[cards.length];
		makeCards();
		cards = shuffle(cards);
	}
	private String getCardTexts() {
		return "Prøv lykken kort: _______rec._1\r\n"
			+ "1_De har vundet i Klasselotteriet.<br />Modtag kr. 500 _500_____Conditioned rec._2\r\n"
			+ "1_De havde en række med<br />elleve rigtige i tipning.<br />Modtag kr. 1000 _1000_____rec. Birthday_3\r\n"
			+ "1_De modtager Deres<br />aktieudbytte. Modtag<br />kr. 1000 af banken. _1000_____pay_4\r\n"
			+ "1_Deres præmieobligation er<br />kommet ud. De modtager<br />kr. 1000 af banken. _1000_____conditioned pay_5\r\n"
			+ "1_Deres præmieobligation er<br />kommet ud. De modtager<br />kr. 1000 af banken. _1000_____Move_6\r\n"
			+ "1_Grundet dyrtiden har De<br />fået gageforhøjelse.<br />Modtag kr. 1000 _1000_____Goto rec.start_7\r\n"
			+ "1_Kommunen har eftergivet<br />et kvartals skat. Hæv i<br />banken kr. 3000 _3000_____Goto shipping_8\r\n"
			+ "1_Modtag udbytte af Deres<br />aktier kr. 1000 _1000_____goto jail_9\r\n"
			+ "1_Modtag udbytte af Deres<br />aktier kr. 1000 _1000_____Get out jail_10\r\n"
			+ "1_Værdien af egen avl fra<br />nyttehaven udgør kr. 200,<br />som De modtager af banken. _200______\r\n"
			+ "2_De modtager<br />Matador-legatet for værdigt<br />trængende, stort kr. 40000.<br />Ved værdigt trængende forstås,<br />at Deres formue, d.v.s. Deres<br />kontante penge + skøder +<br />bygninger ikke overstiger<br />kr. 15000 _40000_15000_____\r\n"
			+ "3_Det er Deres fødselsdag.<br />Modtag af hver medspiller<br />kr. 200 _200______\r\n"
			+ "4_Betal Deres bilforsikring -<br />kr. 1000 _1000______\r\n"
			+ "4_Betal kr. 3000 for reparation<br />af Deres vogn. _3000______\r\n"
			+ "4_Betal kr. 3000 for reparation<br />af Deres vogn. _3000______\r\n"
			+ "4_De har kørt frem for >>Fuldt<br />Stop<<. Betal kr. 1000 i bøde. _1000______\r\n"
			+ "4_De har modtaget Deres<br />tandlægeregning.<br />Betal kr. 2000 _2000______\r\n"
			+ "4_De har fået en parkeringsbøde.<br />Betal kr. 200 i bøde. _200______\r\n"
			+ "4_De har været en tur i udlandet<br />og haft for mange cigaretter<br />med hjem. Betal told kr. 200 _200______\r\n"
			+ "5_Ejendomsskatterne er steget.<br />Ekstraudgifterne er:<br />kr 800 pr. hus<br /> kr 2300 pr. hotel. _800_2300_____\r\n"
			+ "5_Oliepriserne er steget,<br />og De skal betale:\\kr. 500 pr. hus<br />kr. 2000 pr. hotel. _500_2000_____\r\n"
			+ "6_Ryk tre felter tilbage. _-3______\r\n"
			+ "7_Ryk frem til Frederiksberg<br />Allé. Hvis De passerer<br />Start inkassér da<br />kr. 4000 _12______\r\n"
			+ "7_Ryk frem til Grønningen.<br />Hvis De passerer Start<br />inkassér da kr. 4000 _25______\r\n"
			+ "7_Ryk frem til start. _1______\r\n"
			+ "7_Tag ind på Rådhuspladsen. _40______\r\n"
			+ "7_Tag med LB-færgerne<br />- flyt brikken frem, og hvis<br />De passerer Start,<br />inkassér da kr. 4000 _6______\r\n"
			+ "8_Ryk brikken frem til det<br />nærmeste rederi og betal<br />ejeren to gange den leje, han<br />ellers er berettiget til. Hvis<br />selskabet ikke ejes af nogen,<br />kan De købe det af banken. _______\r\n"
			+ "8_Ryk brikken frem til det<br />nærmeste rederi og betal<br />ejeren to gange den leje, han<br />ellers er berettiget til. Hvis<br />selskabet ikke ejes af nogen,<br />kan De købe det af banken. _______\r\n"
			+ "9_Gå i fængsel. Ryk direkte til<br />fængslet. Selv om De passerer<br />Start, indkassere De<br />ikke kr. 4000 _______\r\n"
			+ "9_Gå i fængsel. Ryk direkte til<br />fængslet. Selv om De passerer<br />Start, indkassere De<br />ikke kr. 4000 _______\r\n"
			+ "10_I anledning af kongens<br />fødselsdag benådes De<br />herved for fængsel.<br />Dette kort kan opbevares,<br />indtil De får brug for det,<br />eller De kan sælge det. _______\r\n"
			+ "10_I anledning af kongens<br />fødselsdag benådes De<br />herved for fængsel.<br />Dette kort kan opbevares,<br />indtil De får brug for det,<br />eller De kan sælge det. _______\r\n";
	}
	private void makeCards() {
		String all = this.getCardTexts();
		for(int i = 1; i < all.split("\r\n").length; i++) {
			String line = all.split("\r\n")[i];
			int type = Integer.parseInt(line.split("_")[0]);
			
			switch(type) {
				case 1:
					makeReceive(i, line);
					break;
				case 2:
					makeConditionedReceived(i, line);
					break;
				case 3:
					makeReceiveBirthday(i, line);
					break;
				case 4:
					makePay(i, line);
					break;
				case 5:
					makeConditionedPay(i, line);
					break;
				case 6:
					makeMove(i, line);
					break;
				case 7:
					makeGoToReceiveStart(i, line);
					break;
				case 8:
					makeGoToShipping(i, line);
					break;
				case 9:
					makeGoToJail(i, line);
					break;
				case 10:
					makeGetOutOfJail(i, line);
					break;
			}
		}
	}
	private void makeReceive(int i, String line) {
		String[] tokens = line.split("_");
		String text = tokens[1].replace("<br />", "\n");
		int amount = Integer.parseInt(tokens[2]);
		cards[i - 1] = new Receive(text, amount);
	}
	private void makeConditionedReceived(int i, String line) {
		String[] tokens = line.split("_");
		String text = tokens[1].replace("<br />", "\n");
		int amount = Integer.parseInt(tokens[2]);
		int povertyLimit = Integer.parseInt(tokens[3]);
		
		cards[i - 1] = new ConditionedReceive(text, amount, povertyLimit);
	}
	private void makeReceiveBirthday(int i, String line) {
		String[] tokens = line.split("_");
		String text = tokens[1].replace("<br />", "\n");
		int amount = Integer.parseInt(tokens[2]);
		
		cards[i - 1] = new ReceiveBirthday(text, amount);
	}
	private void makePay(int i, String line) {
		String[] tokens = line.split("_");
		String text = tokens[1].replace("<br />", "\n");
		int amount = Integer.parseInt(tokens[2]);
		
		cards[i - 1] = new Pay(text, amount);
	}
	private void makeConditionedPay(int i, String line) {
		String[] tokens = line.split("_");
		String text = tokens[1].replace("<br />", "\n");
		int amount = Integer.parseInt(tokens[2]);
		int hotelAmount = Integer.parseInt(tokens[3]);
		
		cards[i - 1] = new ConditionedPay(text, amount, hotelAmount);
	}
	private void makeMove(int i, String line) {
		String[] tokens = line.split("_");
		String text = tokens[1].replace("<br />", "\n");
		int distance = Integer.parseInt(tokens[2]);
		
		cards[i - 1] = new Move(text, distance);
	}
	private void makeGoToReceiveStart(int i, String line) {
		String[] tokens = line.split("_");
		String text = tokens[1].replace("<br />", "\n");
		int position = Integer.parseInt(tokens[2]);
		
		cards[i - 1] = new GoToReceiveStart(text, position);
	}
	private void makeGoToShipping(int i, String line) {
		String[] tokens = line.split("_");
		String text = tokens[1].replace("<br />", "\n");
		
		cards[i - 1] = new GoToShipping(text);
	}
	private void makeGoToJail(int i, String line) {
		String[] tokens = line.split("_");
		String text = tokens[1].replace("<br />", "\n");
		
		cards[i - 1] = new GoToJail(text);
	}
	private void makeGetOutOfJail(int i, String line) {
		// TODO ver.2: Get out of jail card is not implemented yet
	}
	/**
	 * Shuffles a list of cards using Durstenfeld algorithm
	 * (a variant of Fisher–Yates shuffle)
	 * @param list A sorted list
	 * @return the same list, but with shuffled content
	 */
	public static Card[] shuffle(Card[] list) {
		Random rand = new Random();
		for(int i = list.length - 1; i >= 1; i--) {
			int index = rand.nextInt(i);
			// Swap
			Card temp = list[i];
			list[i] = list[index];
			list[index] = temp;
		}
		return list;
	}
	public static Card draw() {
		int counter = 0;
		for(int i = 0; i < cards.length; i++) {
			if(cards[i] != null) counter++;
			if(discarded[i] != null) counter++;
		}
		if(counter == 0) {
			Boundary
				.showMessage("No cards exists in game please add at least one to the deck. Exiting...");
			System.exit(0);
		}
		
		for(int i = 0; i < cards.length; i++) {
			Card card = cards[i];
			if(card != null) {
				cards[i] = null;
				return card;
			}
		}
		cards = shuffle(discarded);
		for(int i = 0; i < discarded.length; i++)
			discarded[i] = null;
		return draw(); // recursion
	}
	public static void returnCard(Card discard) {
		int i = 0;
		while(discarded[i] != null)
			i++;
		discarded[i] = discard;
	}
	
	/**
	 * Tests if shuffle is truely random...
	 * @param args
	 */
	@SuppressWarnings("unused")
	private static void testShuffle() {
		Card[] list = new Card[10];
		for(int i = 0; i < list.length; i++) {
			list[i] = new Card("" + i) {
				@Override
				public void execute(Player player) {/* Do nothing */}
			};
		}
		
		int[] g = new int[list.length];
		for(int i = 0; i < 100000; i++) {
			list = shuffle(list);
			for(int j = 0; j < list.length; j++) {
				if(list[j].toString().contains("0")) g[j]++;
			}
		}
		for(int a : g) {
			System.out.println(a);
		}
		
		// Shuffles the list and prints it
		System.out.println("\nAnd one more time...");
		list = shuffle(list);
		for(Card c : list) {
			System.out.println(c);
		}
	}
}